/*
 * Copyright (c) 2014 Luca Agostini, Alessandro Cantini, Alessandro Dignani
 *
 * This file is part of MeteoCal.
 *
 * MeteoCal is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package it.polimi.se2.agostini_cantini_dignani.meteocal.util;

import it.polimi.se2.agostini_cantini_dignani.meteocal.business.WeatherForecastManager;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * This class sends Http requests and manages responses.
 *
 * @author Luca Agostini <luca1.agostini@mail.polimi.it>
 */
public class HttpRequest {

	private static final Logger LOGGER = Logger.getLogger(HttpRequest.class.getName());

	private static final String FORECAST_URL = "http://api.openweathermap.org/data/2.5/forecast/daily?";
	private static final String FORECAST_MODE = "&cnt=" + WeatherForecastManager.DAYS_TO_FORECAST + "&mode=json";
	private static final String CURRENT_WEATHER_URL = "http://api.openweathermap.org/data/2.5/weather?";
	private static final String GEOCODING_URL = "https://maps.googleapis.com/maps/api/geocode/json?address=";
	private static final String GEOCODING_KEY = "&key=AIzaSyADT_tMha0rBJ6uB1xGMlIP3mXDH9amDdQ";

	private HttpRequest() {
	}

	/**
	 * Sends an http request to openweathermap API for a specified location and returns the http
	 * result.
	 *
	 * @param place the location of the current weather
	 * @return the http result; this response is not parsed yet
	 */
	public static String getCurrentWeather(String place) {
		String coordString = retrieveCoordinates(place);
		String url = CURRENT_WEATHER_URL + coordString;
		return getResponse(url);
	}

	/**
	 * Sends an http request to openweathermap API for a specified location and returns the http
	 * result.
	 *
	 * @param place the location of the weather forecast
	 * @return the http result; this response is not parsed yet
	 */
	public static String getWeatherData(String place) {
		String coordString = retrieveCoordinates(place);
		if (coordString == null) {
			return null;
		}
		String url = FORECAST_URL + coordString + FORECAST_MODE;
		return getResponse(url);
	}

	private static HttpURLConnection connectToUrl(String url) {
		HttpURLConnection con;
		try {
			con = (HttpURLConnection) (new URL(url)).openConnection();
			con.setRequestMethod("GET");
			con.setDoInput(true);
			con.setDoOutput(true);
			con.connect();
		} catch (IOException e) {
			LOGGER.log(Level.WARNING, "The following URL is unreachable: {0}", url);
			return null;
		}

		return con;
	}

	private static String getResponse(String url) {
		InputStream is = null;
		HttpURLConnection con = null;
		StringBuilder buffer = null;
		try {
			con = connectToUrl(url);
			if (con == null) {
				return null;
			}
			buffer = new StringBuilder();
			is = con.getInputStream();
			BufferedReader br = new BufferedReader(new InputStreamReader(is));
			String line = null;
			while ((line = br.readLine()) != null) {
				buffer.append(line).append("\r\n");
			}
		} catch (IOException e) {
			LOGGER.log(Level.SEVERE, "Error getting response.");
		} finally {
			try {
				if (is != null) {
					is.close();
				}
			} catch (IOException e) {
				LOGGER.log(Level.SEVERE, "Error closing input stream.");
			}
			if (con != null) {
				con.disconnect();
			}
		}
		return buffer.toString();
	}

	private static String retrieveCoordinates(String place) {
		String loc_request = place.replace(" ", "+");
		String url = GEOCODING_URL + loc_request + GEOCODING_KEY;
		String data = getResponse(url);

		double[] coordinates = new double[2];

		try {
			JSONObject jObj = new JSONObject(data);
			JSONArray result = jObj.getJSONArray("results");
			JSONObject sys = result.getJSONObject(0);
			JSONObject location = sys.getJSONObject("geometry").getJSONObject("location");
			coordinates[0] = location.getDouble("lat");
			coordinates[1] = location.getDouble("lng");
		} catch (JSONException e) {
			LOGGER.log(Level.WARNING, "Error parsing geocoding data.");
			return null;
		}

		return "lat=" + coordinates[0] + "&lon=" + coordinates[1];
	}
}
